package com.imdroid.carac.speechRecog;

import android.media.AudioFormat;
import android.media.AudioRecord;
import android.media.MediaRecorder;
import android.util.Log;
import edu.cmu.pocketsphinx.Decoder;
import edu.cmu.pocketsphinx.Hypothesis;

class SpeechRecogThread {

	private static enum State {
		IDLE, WORK
	};

	private static enum Message {
		start, stop
	};

//	 static final int SAMPLE_RATE = 20000;
	public static int SAMPLE_RATE = 11025;
	private static State state = State.IDLE;
	private static Message message;
	private static Hypothesis result;

	static {
		System.loadLibrary("pocketsphinx_jni");

		DecoderPool.init();

		new Thread() {
			public void run() {
				threadRun();
			}
		}.start();
	}

	static void init() {
	}

	synchronized static void start() {
		message = Message.start;
		SpeechRecogThread.class.notifyAll();
		while (message != null)
			try {
				SpeechRecogThread.class.wait();
			} catch (InterruptedException e) {
				throw new RuntimeException(e);
			}
	}

	synchronized static Hypothesis stop() {
		message = Message.stop;
		SpeechRecogThread.class.notifyAll();
		while (message != null)
			try {
				SpeechRecogThread.class.wait();
			} catch (InterruptedException e) {
				throw new RuntimeException(e);
			}
		return result;
	}

	private static void threadRun() {
		Decoder decoder = null;
		AudioRecord audioRecord = null;

		short[] buf = new short[10 * 1024];

		while (true) {
			boolean work = false;
			synchronized (SpeechRecogThread.class) {
				if (state == State.IDLE && message == null) {
					try {
						SpeechRecogThread.class.wait();
					} catch (InterruptedException e) {
						throw new RuntimeException(e);
					}
					continue;

				} else if (state == State.IDLE && message == Message.start) {
					decoder = DecoderPool.fetch();
					decoder.startUtt();
					audioRecord = new AudioRecord(
							MediaRecorder.AudioSource.MIC, // 山寨5寸6577系统4.1.9上用default才不报错
							SAMPLE_RATE, AudioFormat.CHANNEL_IN_MONO,
							AudioFormat.ENCODING_PCM_16BIT, 100 * 1024);
					audioRecord.startRecording();
					state = State.WORK;
					SpeechRecogThread.class.notifyAll();

				} else if (state == State.IDLE && message == Message.stop) {
					Log.e(SpeechRecogThread.class.getName(),
							"message stop when state IDLE, forget to call start() ?");
					SpeechRecogThread.class.notifyAll();

				} else if (state == State.WORK && message == null) {
					// if( System.currentTimeMillis() - startTime > 10*1000 ) {
					// Log.e( SpeechRecognize.class.getName(), "time up" );
					// audioRecord.stop();
					// decoder.endUtt();
					// result = decoder.getHyp();
					// decoder = null;
					// state = State.IDLE;
					// } else {
					// work = true;
					// }
					work = true;

				} else if (state == State.WORK && message == Message.start) {
					Log.e(SpeechRecogThread.class.getName(),
							"message start when state WORK, repeated call start() has no effect");
					SpeechRecogThread.class.notifyAll();

				} else if (state == State.WORK && message == Message.stop) {
					audioRecord.stop();
					while (true) {
						int len = audioRecord.read(buf, 0, buf.length);
						if (len == 0)
							break;
						if (len < 0)
							throw new RuntimeException("" + len);
						decoder.processRaw(buf, len, false, false);
					}
					decoder.endUtt();
					result = decoder.getHyp();
					decoder = null;
					audioRecord.release();
					audioRecord = null;
					state = State.IDLE;
					SpeechRecogThread.class.notifyAll();
				}

				message = null;
			}

			if (work == false)
				continue;
			int len = audioRecord.read(buf, 0, buf.length);
			if (len < 0)
				throw new RuntimeException("" + len);
			decoder.processRaw(buf, len, false, false);
		}
	}

	// long time = System.currentTimeMillis();
	// Log.e("3",""+String.format("%.2fs",(System.currentTimeMillis()-time)/1e3));time=System.currentTimeMillis();

	// // AudioTrack.MODE_STATIC
	// 模式下，数据一次性传到缓冲区，缓冲区太小会导致声音放不完，setNotificationMarkerPosition也收不到消息
	// AudioTrack audioTrack = new AudioTrack( AudioManager.STREAM_VOICE_CALL,
	// SAMPLE_RATE, AudioFormat.CHANNEL_OUT_DEFAULT,
	// AudioFormat.ENCODING_PCM_16BIT,
	// 1024*1024, AudioTrack.MODE_STATIC );
	// audioTrack.write( buf, 0, p );
	// audioTrack.setNotificationMarkerPosition( p );
	// audioTrack.setPlaybackPositionUpdateListener( new
	// OnPlaybackPositionUpdateListener() {
	// public void onPeriodicNotification(AudioTrack track) {}
	// public void onMarkerReached( AudioTrack track ) {
	// track.stop();
	// track.release();
	// }
	// } );
	// audioTrack.play();
}
